﻿using System;
using System.Net;
using System.Net.Mail;
using Xenta.Attributes;
using Xenta.Entities;
using Xenta.Operations;
using Xenta.Utils;

namespace Xenta.Plugins
{
    [Dependency("37b5b211-3d87-439e-945e-010a336d44e1", 
        Name = "SMTP Message Sender")]
    public sealed class SmtpMessageSender : IMessageSender, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private string _host;
        private int _port;
        private string _user;
        private string _password;
        private bool _sslEnabled;
        private bool _htmlAllowed;

        #endregion

        #region Ctors

        public SmtpMessageSender(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("37b5b211-3d87-439e-945e-010a336d44e1"),
                    IsSafe = true
                });

                try
                {
                    _host = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Plugin").Of(this).Name("Host")
                    }).Result;
                    _port = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Plugin").Of(this).Name("Port")
                    }).ResultAs<Int32>();
                    _user = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Plugin").Of(this).Name("User")
                    }).Result;
                    _password = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Plugin").Of(this).Name("Password")
                    }).Result;
                    _sslEnabled = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Plugin").Of(this).Name("SslEnabled")
                    }).ResultAs<Boolean>();
                    _htmlAllowed = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Plugin").Of(this).Name("HtmlAllowed")
                    }).ResultAs<Boolean>();

                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                    throw;
                }
            }
        }

        public int Send(MessageEntity message)
        {
            if(message == null)
                throw new ArgumentNullException("message");

            int ret = 0;
            try
            {
                using(var smtp = new SmtpClient(_host, _port)
                {
                    EnableSsl = _sslEnabled,
                    Credentials = new NetworkCredential(_user, _password)
                })
                {
                    string text = HtmlUtility.Decode(message.Text);
                    if(!_htmlAllowed)
                        text = HtmlUtility.ToPlainText(text);

                    using(var email = new MailMessage(message.From, message.To, message.Subject, text))
                    {
                        email.IsBodyHtml = _htmlAllowed;

                        if(!String.IsNullOrWhiteSpace(message.BccTo))
                            email.Bcc.Add(message.BccTo);
                        if(!String.IsNullOrWhiteSpace(message.ReplyTo))
                            email.ReplyToList.Add(message.ReplyTo);
                        smtp.Send(email);
                        ret = 1;
                    }
                }
            }
            catch(SmtpException ex)
            {
                if(ex.StatusCode != SmtpStatusCode.MailboxBusy)
                    ret = -3;
            }
            catch(FormatException)
            {
                ret = -2;
            }
            catch(Exception)
            {
                ret = -1;
            }
            return ret;
        }

        #endregion
    }
}
